﻿//ExchangeBoard.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.BusinessEntities
{
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Reflection;
	using System.Runtime.Serialization;
	using System.Xml.Serialization;

	using Ecng.Collections;
	using Ecng.Common;
	using Ecng.ComponentModel;
	using Ecng.Serialization;
	using Ecng.Reflection;

	/// <summary>
	/// Информация о биржевой площадке.
	/// </summary>
	[Serializable]
	[System.Runtime.Serialization.DataContract]
	[Ignore(FieldName = "IsDisposed")]
	public class ExchangeBoard : Equatable<ExchangeBoard>, IExtendableEntity
	{
		private static readonly CachedSynchronizedDictionary<string, ExchangeBoard> _boards = new CachedSynchronizedDictionary<string, ExchangeBoard>(StringComparer.InvariantCultureIgnoreCase);

		static ExchangeBoard()
		{
			Test = new ExchangeBoard
			{
				Code = "TEST",
				Exchange = Exchange.Test,
			};

			// http://stocksharp.com/forum/yaf_postst667_Rabochiie-dni-dlia-birzh--2011-ghod.aspx
			// http://stocksharp.com/forum/yaf_postst1689_Exchange-WorkingTime-2012.aspx
			var specialWorkingDays = new[]
			{
				new DateTime(2011, 3, 5),
				
				new DateTime(2012, 3, 11),
				new DateTime(2012, 4, 28),
				new DateTime(2012, 6, 9),
				new DateTime(2012, 12, 29)
			};

			var specialHolidays = new[]
			{
				new DateTime(2011, 1, 3),
				new DateTime(2011, 1, 4),
				new DateTime(2011, 1, 5),
				new DateTime(2011, 1, 6),
				new DateTime(2011, 1, 7),
				new DateTime(2011, 1, 10),
				new DateTime(2011, 2, 23),
				new DateTime(2011, 3, 7),
				new DateTime(2011, 3, 8),
				new DateTime(2011, 5, 2),
				new DateTime(2011, 5, 9),
				new DateTime(2011, 6, 13),
				new DateTime(2011, 11, 4),

				new DateTime(2012, 1, 2),
				new DateTime(2012, 3, 8),
				new DateTime(2012, 3, 9),
				new DateTime(2012, 4, 30),
				new DateTime(2012, 5, 1),
				new DateTime(2012, 5, 9),
				new DateTime(2012, 6, 11),
				new DateTime(2012, 6, 12),
				new DateTime(2012, 11, 5),
				new DateTime(2012, 12, 31),

				new DateTime(2013, 1, 1),
				new DateTime(2013, 1, 2),
				new DateTime(2013, 1, 3),
				new DateTime(2013, 1, 4),
				new DateTime(2013, 1, 7),
				new DateTime(2013, 3, 8),
				new DateTime(2013, 5, 1),
				new DateTime(2013, 5, 2),
				new DateTime(2013, 5, 3),
				new DateTime(2013, 5, 9),
				new DateTime(2013, 5, 10),
				new DateTime(2013, 6, 12)
			};

			Forts = new ExchangeBoard
			{
				Code = "FORTS",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("10:00:00".To<TimeSpan>(), "14:00:00".To<TimeSpan>()),
						new Range<TimeSpan>("14:03:00".To<TimeSpan>(), "18:45:00".To<TimeSpan>()),
						new Range<TimeSpan>("19:00:00".To<TimeSpan>(), "23:50:00".To<TimeSpan>())
					},
					SpecialWorkingDays = ArrayHelper.Clone(specialWorkingDays),
					SpecialHolidays = ArrayHelper.Clone(specialHolidays),
				},
				ExpiryTime = new TimeSpan(18, 45, 00),
				IsSupportAtomicReRegister = true,
				Exchange = Exchange.Me,
			};

			Micex = new ExchangeBoard
			{
				Code = "MICEX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("10:00:00".To<TimeSpan>(), "18:45:00".To<TimeSpan>())
					},
					SpecialWorkingDays = ArrayHelper.Clone(specialWorkingDays),
					SpecialHolidays = ArrayHelper.Clone(specialHolidays),
				},
				IsSupportMarketOrders = true,
				Exchange = Exchange.Me,
			};

			Ux = new ExchangeBoard
			{
				Code = "UX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("10:30:00".To<TimeSpan>(), "13:00:00".To<TimeSpan>()),
						new Range<TimeSpan>("13:03:00".To<TimeSpan>(), "17:30:00".To<TimeSpan>())
					}
				},
				ExpiryTime = new TimeSpan(18, 45, 00),
				IsSupportAtomicReRegister = true,
				Exchange = Exchange.Ux
			};

			Nyse = new ExchangeBoard
			{
				Code = "NYSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "16:00:00".To<TimeSpan>())
					}
				},
				IsSupportMarketOrders = true,
				Exchange = Exchange.Nyse
			};

			Nasdaq = new ExchangeBoard
			{
				Code = "NASDAQ",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "16:00:00".To<TimeSpan>())
					}
				},
				IsSupportMarketOrders = true,
				Exchange = Exchange.Nasdaq,
			};

			Tsx = new ExchangeBoard
			{
				Code = "TSX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "16:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Tsx,
			};

			Lse = new ExchangeBoard
			{
				Code = "LSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("08:00:00".To<TimeSpan>(), "16:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Lse,
			};

			Tse = new ExchangeBoard
			{
				Code = "TSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:00:00".To<TimeSpan>(), "11:30:00".To<TimeSpan>()),
						new Range<TimeSpan>("12:30:00".To<TimeSpan>(), "15:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Tse,
			};

			Hkex = new ExchangeBoard
			{
				Code = "HKEX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:20:00".To<TimeSpan>(), "12:00:00".To<TimeSpan>()),
						new Range<TimeSpan>("13:00:00".To<TimeSpan>(), "16:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Hkex,
			};

			Hkfe = new ExchangeBoard
			{
				Code = "HKFE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:15:00".To<TimeSpan>(), "12:00:00".To<TimeSpan>()),
						new Range<TimeSpan>("13:00:00".To<TimeSpan>(), "16:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Hkfe,
			};

			Sse = new ExchangeBoard
			{
				Code = "SSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "11:30:00".To<TimeSpan>()),
						new Range<TimeSpan>("13:00:00".To<TimeSpan>(), "15:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Sse,
			};

			Szse = new ExchangeBoard
			{
				Code = "SZSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "11:30:00".To<TimeSpan>()),
						new Range<TimeSpan>("13:00:00".To<TimeSpan>(), "15:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Szse
			};

			Tsec = new ExchangeBoard
			{
				Code = "TSEC",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:00:00".To<TimeSpan>(), "13:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Tsec,
			};

			Sgx = new ExchangeBoard
			{
				Code = "SGX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:00:00".To<TimeSpan>(), "17:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Sgx,
			};

			Pse = new ExchangeBoard
			{
				Code = "PSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "12:00:00".To<TimeSpan>()),
						new Range<TimeSpan>("13:30:00".To<TimeSpan>(), "15:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Pse,
			};

			Myx = new ExchangeBoard
			{
				Code = "MYX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:00:00".To<TimeSpan>(), "12:30:00".To<TimeSpan>()),
						new Range<TimeSpan>("14:00:00".To<TimeSpan>(), "17:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Myx,
			};

			Idx = new ExchangeBoard
			{
				Code = "IDX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "16:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Idx,
			};

			Set = new ExchangeBoard
			{
				Code = "SET",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("10:00:00".To<TimeSpan>(), "12:30:00".To<TimeSpan>()),
						new Range<TimeSpan>("14:30:00".To<TimeSpan>(), "16:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Set,
			};

			Bse = new ExchangeBoard
			{
				Code = "BSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:15:00".To<TimeSpan>(), "15:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Bse,
			};

			Nse = new ExchangeBoard
			{
				Code = "NSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:15:00".To<TimeSpan>(), "15:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Nse,
			};

			Cse = new ExchangeBoard
			{
				Code = "CSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:30:00".To<TimeSpan>(), "14:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Cse,
			};

			Krx = new ExchangeBoard
			{
				Code = "KRX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:00:00".To<TimeSpan>(), "15:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Krx,
			};

			Asx = new ExchangeBoard
			{
				Code = "ASX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:50:00".To<TimeSpan>(), "16:12:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Asx,
			};

			Nzsx = new ExchangeBoard
			{
				Code = "NZSX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("10:00:00".To<TimeSpan>(), "17:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Nzsx,
			};

			Tase = new ExchangeBoard
			{
				Code = "TASE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("09:00:00".To<TimeSpan>(), "16:25:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Tase,
			};

			Fwb = new ExchangeBoard
			{
				Code = "FWB",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("08:00:00".To<TimeSpan>(), "22:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Fwb,
			};

			Mse = new ExchangeBoard
			{
				Code = "MSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("9:00:00".To<TimeSpan>(), "17:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Mse,
			};

			Swx = new ExchangeBoard
			{
				Code = "SWX",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("9:00:00".To<TimeSpan>(), "17:30:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Swx,
			};

			Jse = new ExchangeBoard
			{
				Code = "JSE",
				WorkingTime = new WorkingTime
				{
					Times = new[]
					{
						new Range<TimeSpan>("9:00:00".To<TimeSpan>(), "17:00:00".To<TimeSpan>())
					}
				},
				Exchange = Exchange.Jse,
			};

			foreach (var prop in typeof(ExchangeBoard).GetMembers<PropertyInfo>(BindingFlags.Public | BindingFlags.Static, typeof(ExchangeBoard)))
			{
				var board = (ExchangeBoard)prop.GetValue(null, null);
				_boards.Add(board.Code, board);
			}
		}

		/// <summary>
		/// Информация о тестовой площадке, не имеющая ограничения в расписание работы.
		/// </summary>
		public static ExchangeBoard Test { get; private set; }

		/// <summary>
		/// Информация о площадке FORTS биржи <see cref="BusinessEntities.Exchange.Me"/>.
		/// </summary>
		public static ExchangeBoard Forts { get; private set; }

		/// <summary>
		/// Информация о площадке ММВБ биржи <see cref="BusinessEntities.Exchange.Me"/>.
		/// </summary>
		public static ExchangeBoard Micex { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Ux"/>.
		/// </summary>
		public static ExchangeBoard Ux { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Nyse"/>.
		/// </summary>
		public static ExchangeBoard Nyse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Nasdaq"/>.
		/// </summary>
		public static ExchangeBoard Nasdaq { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Lse"/>.
		/// </summary>
		public static ExchangeBoard Lse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Tse"/>.
		/// </summary>
		public static ExchangeBoard Tse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Hkex"/>.
		/// </summary>
		public static ExchangeBoard Hkex { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Hkfe"/>.
		/// </summary>
		public static ExchangeBoard Hkfe { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Sse"/>.
		/// </summary>
		public static ExchangeBoard Sse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Szse"/>.
		/// </summary>
		public static ExchangeBoard Szse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Tsx"/>.
		/// </summary>
		public static ExchangeBoard Tsx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Fwb"/>.
		/// </summary>
		public static ExchangeBoard Fwb { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Asx"/>.
		/// </summary>
		public static ExchangeBoard Asx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Nzsx"/>.
		/// </summary>
		public static ExchangeBoard Nzsx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Bse"/>.
		/// </summary>
		public static ExchangeBoard Bse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Nse"/>.
		/// </summary>
		public static ExchangeBoard Nse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Swx"/>.
		/// </summary>
		public static ExchangeBoard Swx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Krx"/>.
		/// </summary>
		public static ExchangeBoard Krx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Mse"/>.
		/// </summary>
		public static ExchangeBoard Mse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Jse"/>.
		/// </summary>
		public static ExchangeBoard Jse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Sgx"/>.
		/// </summary>
		public static ExchangeBoard Sgx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Tsec"/>.
		/// </summary>
		public static ExchangeBoard Tsec { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Pse"/>.
		/// </summary>
		public static ExchangeBoard Pse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Myx"/>.
		/// </summary>
		public static ExchangeBoard Myx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Idx"/>.
		/// </summary>
		public static ExchangeBoard Idx { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Set"/>.
		/// </summary>
		public static ExchangeBoard Set { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Cse"/>.
		/// </summary>
		public static ExchangeBoard Cse { get; private set; }

		/// <summary>
		/// Информация о площадке биржи <see cref="BusinessEntities.Exchange.Tase"/>.
		/// </summary>
		public static ExchangeBoard Tase { get; private set; }

		/// <summary>
		/// Создать <see cref="ExchangeBoard"/>.
		/// </summary>
		public ExchangeBoard()
		{
			ExtensionInfo = new Dictionary<object, object>();
		}

		private string _code;

		/// <summary>
		/// Код площадки.
		/// </summary>
		[DataMember]
		[Identity]
		[DisplayName("Код")]
		[Description("Код площадки.")]
		[Category("Основные")]
		public string Code
		{
			get { return _code; }
			set
			{
				if (Code == value)
					return;

				_code = value;
				this.Notify("Code");
			}
		}

		private TimeSpan _expiryTime;

		/// <summary>
		/// Время экспирации инструментов.
		/// </summary>
		[TimeSpan]
		[DataMember]
		[DisplayName("Экспирация")]
		[Description("Время экспирации инструментов.")]
		[Category("Основные")]
		public TimeSpan ExpiryTime
		{
			get { return _expiryTime; }
			set
			{
				if (ExpiryTime == value)
					return;

				_expiryTime = value;
				this.Notify("ExpiryTime");
			}
		}

		/// <summary>
		/// Биржа, на которой расположена площадка.
		/// </summary>
		[RelationSingle(IdentityType = typeof(string))]
		[DataMember]
		[DisplayName("Биржа")]
		[Description("Биржа, на которой расположена площадка.")]
		[Category("Основные")]
		public Exchange Exchange { get; set; }

		private bool _isSupportAtomicReRegister;

		/// <summary>
		/// Поддерживается ли перерегистрация заявок через метод <see cref="ITrader.ReRegisterOrder(StockSharp.BusinessEntities.Order,StockSharp.BusinessEntities.Order)"/>
		/// в виде одной транзакции.
		/// </summary>
		[DataMember]
		[DisplayName("Перерегистрация")]
		[Description("Поддерживается ли перерегистрация заявок в виде одной транзакции.")]
		[Category("Основные")]
		public bool IsSupportAtomicReRegister
		{
			get { return _isSupportAtomicReRegister; }
			set
			{
				_isSupportAtomicReRegister = value;
				this.Notify("IsSupportAtomicReRegister");
			}
		}

		private bool _isSupportMarketOrders;

		/// <summary>
		/// Поддерживается ли рыночный тип заявок <see cref="OrderTypes.Market"/>.
		/// </summary>
		[DataMember]
		[DisplayName("Рыночные заявки")]
		[Description("Поддерживается ли рыночный тип заявок.")]
		[Category("Основные")]
		public bool IsSupportMarketOrders
		{
			get { return _isSupportMarketOrders; }
			set
			{
				_isSupportMarketOrders = value;
				this.Notify("IsSupportMarketOrders");
			}
		}

		private WorkingTime _workingTime = new WorkingTime();

		/// <summary>
		/// Время работы площадки.
		/// </summary>
		[DataMember]
		[DisplayName("Время работы")]
		[Description("Время работы площадки.")]
		[Category("Основные")]
		public WorkingTime WorkingTime
		{
			get { return _workingTime; }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				if (WorkingTime == value)
					return;

				_workingTime = value;
				this.Notify("WorkingTime");
			}
		}

		/// <summary>
		/// Все площадки.
		/// </summary>
		public static ExchangeBoard[] AllBoards
		{
			get { return _boards.CachedValues; }
		}

		/// <summary>
		/// Получить площадку по ее коду.
		/// </summary>
		/// <param name="code">Код площадки.</param>
		/// <param name="createBoard">Создать площадку, если она не найдена.</param>
		/// <returns>Найденная площадка. Если площадки с переданным названием не существует и <paramref name="createBoard"/> равен null, то будет возвращено null.</returns>
		public static ExchangeBoard GetBoard(string code, Func<string, ExchangeBoard> createBoard = null)
		{
			lock (_boards.SyncRoot)
			{
				var board = _boards.TryGetValue(code);

				if (board != null)
					return board;

				if (createBoard != null)
				{
					board = createBoard(code);
					_boards.Add(board.Code, board);
				}

				return board;
			}
		}

		[field: NonSerialized]
		private IDictionary<object, object> _extensionInfo;

		/// <summary>
		/// Расширенная информация по бирже.
		/// </summary>
		/// <remarks>
		/// Необходима в случае хранения в программе дополнительной информации, ассоциированной с биржей.
		/// </remarks>
		[XmlIgnore]
		[Browsable(false)]
		public IDictionary<object, object> ExtensionInfo
		{
			get { return _extensionInfo; }
			set { _extensionInfo = value; }
		}

		[field: NonSerialized]
		private PropertyChangedEventHandler _propertyChanged;

		event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
		{
			add { _propertyChanged += value; }
			remove { _propertyChanged -= value; }
		}

		void INotifyPropertyChangedEx.NotifyPropertyChanged(string info)
		{
			_propertyChanged.SafeInvoke(this, info);
		}

		/// <summary>
		/// Получить строковое представление.
		/// </summary>
		/// <returns>Строковое представление.</returns>
		public override string ToString()
		{
			return Code;
		}

		/// <summary>
		/// Сравнить два объекта <see cref="ExchangeBoard" /> на эквивалентность.
		/// </summary>
		/// <param name="other">Объект для сравнения.</param>
		/// <returns>true, если другой объект равен текущему, иначе false.</returns>
		protected override bool OnEquals(ExchangeBoard other)
		{
			return Code == other.Code;
		}

		/// <summary>
		/// Рассчитать хеш-код объекта <see cref="ExchangeBoard"/>.
		/// </summary>
		/// <returns>Хеш-код.</returns>
		public override int GetHashCode()
		{
			return Code.GetHashCode();
		}

		/// <summary>
		/// Создать копию объекта <see cref="ExchangeBoard" />.
		/// </summary>
		/// <returns>Копия.</returns>
		public override ExchangeBoard Clone()
		{
			return new ExchangeBoard
			{
				Exchange = Exchange,
				Code = Code,
				IsSupportAtomicReRegister = IsSupportAtomicReRegister,
				IsSupportMarketOrders = IsSupportMarketOrders,
				ExpiryTime = ExpiryTime,
				WorkingTime = WorkingTime.Clone(),
			};
		}
	}
}